# 方法一：

import numpy as np

import pandas as pd

import sympy as sp

import random

from matplotlib import pyplot as plt

# 读取Excel文件

df = pd.read_excel('class/the house data2.xlsx')  # 确保文件路径正确

# 读取房屋面积和距离地铁站的数据

x1 = df['房屋面积'].values  # 房屋面积
x2 = df['距离最近地铁站的距离'].values  # 距地铁站距离
y_true = df['房屋价格'].values  # 房屋价格（真实值）

# 标准化自变量

x1 = (x1 - x1.mean()) / x1.std()

x2 = (x2 - x2.mean()) / x2.std()

# 定义符号变量

k1, k2, b = sp.symbols('k1 k2 b')

y_pred_sym = k1 * x1 + k2 * x2 + b  # 预测的y值（线性回归模型）

# 定义均方误差损失函数

mse_sym = ((y_pred_sym - y_true)**2).mean()

# 求损失函数对k1, k2, b的偏导数

dk1_mse = sp.diff(mse_sym, k1)

dk2_mse = sp.diff(mse_sym, k2)

db_mse = sp.diff(mse_sym, b)

# 初始化参数

k1_val = random.uniform(-10, 10)

k2_val = random.uniform(-10, 10)

b_val = random.uniform(-10, 10)

iterations = 5000

learning_rate = 0.01

# 梯度下降更新参数

for i in range(iterations):

    dk1_mse_val = dk1_mse.subs({k1: k1_val, k2: k2_val, b: b_val})

    dk2_mse_val = dk2_mse.subs({k1: k1_val, k2: k2_val, b: b_val})

    db_mse_val = db_mse.subs({k1: k1_val, k2: k2_val, b: b_val})

    

    k1_val = k1_val - dk1_mse_val * learning_rate

    k2_val = k2_val - dk2_mse_val * learning_rate

    b_val = b_val - db_mse_val * learning_rate

# 输出最终的k1, k2, b值及最小损失

print(f"k1: {k1_val}, k2: {k2_val}, b: {b_val}")

print(f"Final MSE: {mse_sym.subs({k1: k1_val, k2: k2_val, b: b_val})}")

# 用最终的参数绘制预测值和真实值的图

y_pred = k1_val * x1 + k2_val * x2 + b_val

plt.scatter(range(len(y_true)), y_true, label="True Prices")

plt.plot(range(len(y_pred)), y_pred, color='red', label="Predicted Prices")

plt.xlabel("Sample Index")

plt.ylabel("Price (¥)")

plt.legend()

plt.show()



# 方法二 把房屋面积、距地铁站距离组成一个大的特征矩阵。该特征矩阵共2列，100行。然后参与计算。

import numpy as np

import pandas as pd

import sympy as sp

import random

from matplotlib import pyplot as plt

# 读取Excel文件

df = pd.read_excel('house_data.xlsx')  # 确保文件路径正确

# 读取房屋面积和距离地铁站的数据

x1 = df['Area (sqm)'].values  # 房屋面积

x2 = df['Distance to Subway (km)'].values  # 距地铁站距离

y_true = df['Price (¥)'].values  # 房屋价格（真实值）

# 将特征组合成一个特征矩阵（n行2列）

X = np.vstack((x1, x2)).T  # 每一行是 [房屋面积, 距地铁站距离]

# 标准化特征矩阵

X = (X - X.mean(axis=0)) / X.std(axis=0)

# 定义符号变量

k = sp.symbols('k:2')  # k是2个元素的向量（对应两个特征的系数）

b = sp.symbols('b')  # 偏置项

# 构建预测函数：y_pred = k1*x1 + k2*x2 + b

y_pred_sym = X @ k + b  # 使用矩阵乘法（符号形式）

# 定义均方误差损失函数

mse_sym = ((y_pred_sym - y_true)**2).mean()

# 对损失函数求k和b的偏导数

dk_mse = [sp.diff(mse_sym, k[i]) for i in range(2)]  # 对每个k的偏导数

db_mse = sp.diff(mse_sym, b)

# 初始化参数

k_val = np.random.uniform(-10, 10, size=2)  # 初始化为2个随机值

b_val = random.uniform(-10, 10)

iterations = 5000

learning_rate = 0.01

# 梯度下降更新参数

for i in range(iterations):

    # 计算偏导数的值

    dk_mse_vals = [dk_mse[j].subs({k[0]: k_val[0], k[1]: k_val[1], b: b_val}) for j in range(2)]

    db_mse_val = db_mse.subs({k[0]: k_val[0], k[1]: k_val[1], b: b_val})

    

    # 更新参数

    k_val -= np.array(dk_mse_vals, dtype=np.float64) * learning_rate

    b_val -= db_mse_val * learning_rate

# 输出最终的k值和b值及最小损失

print(f"k: {k_val}, b: {b_val}")

print(f"Final MSE: {mse_sym.subs({k[0]: k_val[0], k[1]: k_val[1], b: b_val})}")

# 用最终的参数预测

y_pred = X @ k_val + b_val

# 绘制预测值和真实值的图

plt.scatter(range(len(y_true)), y_true, label="True Prices")

plt.plot(range(len(y_pred)), y_pred, color='red', label="Predicted Prices")

plt.xlabel("Sample Index")

plt.ylabel("Price (¥)")

plt.legend()

plt.show()